﻿using AutoMapper;
using Commons.Responses;
using DomainCommons.Models;
using IApplicationServices;
using IRepositories;
using ORM;
using System.Linq.Expressions;

namespace ApplicationService
{
    public class BaseApplicationService<T, TEntity, TApiEntity> : IBaseApplicationService<T, TEntity, TApiEntity>
        where TEntity : class, IEntity<T>, new()
        where TApiEntity : class, IEntity<T>, new()
    {
        private readonly IBaseRepository<T, TEntity> _repository;
        private readonly IMapper _mapper;
        public BaseApplicationService(IBaseRepository<T, TEntity> repository, IMapper mapper)
        {
            _repository = repository;
            _mapper = mapper;
        }
        public PSPDbContext Context { get => _repository.Context; }
        public IBaseRepository<T, TEntity> Repository { get => _repository; }
        public IMapper Mapper { get => _mapper; }

        public virtual async Task<MessageResponse> AddAsync(TApiEntity apiBo)
        {
            var bo =  _mapper.Map<TEntity>(apiBo);
            var res =  await _repository.AddAsync(bo);
            return new MessageResponse(res.Message, res.Successed);

        }

        public async Task<MessageResponse> AddTOtherAsync<Tid, TOther, TApiOher>(TApiOher request) 
            where TOther : class, IEntity<Tid>, new() where TApiOher : class, IEntity<Tid>, new()
        {
            var bo = _mapper.Map<TOther>(request);
            return await _repository.AddOtherAsync<Tid, TOther>(bo);
        }

        public virtual async Task<DatasResponse<TApiEntity>> GetAllAsync(Expression<Func<TEntity, bool>> predicate)
        {
            var bos = await _repository.GetAllAsync(predicate);
            var apibos = _mapper.Map<List<TApiEntity>>(bos.Datas);
            return new DatasResponse<TApiEntity>(bos.Total,apibos);
        }
        public virtual async Task<DatasResponse<TApiEntity>> GetAllAsync()
        {
            var bos = await _repository.GetAllAsync();
            var apibos = _mapper.Map<List<TApiEntity>>(bos.Datas);
            return new DatasResponse<TApiEntity>(bos.Total, apibos);
        }

        public async Task<DataResponse<TApiEntity>> GetAsync(Expression<Func<TEntity, bool>> predicate)
        {
            var bo = await _repository.GetAsync(predicate);
            var apibo = _mapper.Map<TApiEntity>(bo);
            return new DataResponse<TApiEntity>(apibo);
        }
        public async Task<DataResponse<TApiOther>> GetOtherAsync<Tid, TOther, TApiOther>(Expression<Func<TOther, bool>> predicate) 
            where TOther : class, IEntity<Tid>, new() where TApiOther : class, IEntity<Tid>, new()
        {
            var bo = (await _repository.GetOtherAsync<Tid, TOther>(predicate)).Data;
            var apibo = _mapper.Map<TApiOther>(bo);
            return new DataResponse<TApiOther>(apibo);
        }

        public virtual async Task<DataResponse<TApiEntity>> GetByIdAsync(T id)
        {
            var bo = await _repository.GetAsync(id);
            var apibo = _mapper.Map<TApiEntity>(bo);
            return new DataResponse<TApiEntity>(apibo);
        }

        public virtual async Task<DatasResponse<TApiEntity>> GetBySelectAsync(int pageIndex, int pageSize, Expression<Func<TEntity, bool>> predicate)
        {
            var bos = await _repository.GetBySelectAsync(pageIndex, pageSize, predicate);
            var apibos = _mapper.Map<List<TApiEntity>>(bos.Datas);
            return new DatasResponse<TApiEntity>(bos.Total, apibos);
        }

        public async Task<bool> HasAsync(T id)
        {
            return await _repository.HasAsync(id);
        }
        public async Task<MessageResponse> DeleteByIdAsync(T id)
        {
            return await _repository.DeleteAsync(id);
        }
        public async Task<MessageResponse> SoftDeleteByIdAsync(T id)
        {
            return await _repository.SoftDeleteAsync(id);
        }

        public async Task<MessageResponse> SoftDeleteRangeByIdAsync(List<T> ids)
        {
            return await _repository.SoftDeleteRangeByIdAsync(ids);
        }

        public async Task<MessageResponse> UpdateAsync(TApiEntity apiBo)
        {
            var bo = _mapper.Map<TEntity>(apiBo);
            bo.Id = apiBo.Id;
            return await _repository.UpdateAsync(bo);
        }
        public async Task<MessageResponse> UpdateOtherAsync<Tid, Other, TApiOther>(TApiOther request ) where Other : class, IEntity<Tid>, new() where TApiOther : class, IEntity<Tid>, new()
        {
            var bo = _mapper.Map<Other>(request);
            bo.Id = request.Id;
            return await _repository.UpdateOtherAsync<Tid, Other>(bo);
        }
    }
}
